/*
 *
 * Copyright 2015 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include <iostream>
#include <memory>
#include <string>
#include <fstream>

#include <grpcpp/grpcpp.h>

#ifdef BAZEL_BUILD
#include "examples/protos/helloworld.grpc.pb.h"
#else
#include "gp.grpc.pb.h"
#endif

#include <unistd.h>
#include <sys/ipc.h>
#include <sys/types.h>
#include <sys/msg.h>
#include <string.h>

#include "/home/hcgy/Documents/esm6800h/app/can_uim.h"
#include "/home/hcgy/Documents/esm6800h/app/common.h"
#include "/home/hcgy/Documents/esm6800h/app/msg_def.h"
#include "/home/hcgy/Documents/esm6800h/test/data_proc/board_data_proc.h"

#include "action_manage.h"
#include "gp_qpcr_server.h"


using namespace std;

#define FILE_DJ_TRACE "/mnt/nandflash/apps/config/dj_trace.txt"



int g_msg_id = -1;

class ModuleServiceImpl final : public Module::Service {

  Status OpenLid(ServerContext* context,const EmptyRequest* request, Response* reply) override {

    int ret = sendModuleMsgToAct(QUEUE_MSG_TYPE_MODULE,0);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    //wait_ack(30,&stMsgQueueAck,reply);
    wait_ack_module(60,&stMsgQueueAck,reply,0);    
    //sleep(60);
    //reply->set_statecode(0);
    printf("OpenLid finished, grpc return\n");
    return Status::OK;
  }

  Status CloseLid(ServerContext* context, const EmptyRequest* request, Response* reply) override {

    int ret = sendModuleMsgToAct(QUEUE_MSG_TYPE_MODULE,1);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    //wait_ack(30,&stMsgQueueAck,reply);  
    //sleep(60);  
    wait_ack_module(60,&stMsgQueueAck,reply,1);

    //reply->set_statecode(0);
    printf("CloseLid finished, grpc return\n");
    return Status::OK;
  }

  Status XR_AToB(ServerContext* context, const EmptyRequest* request, Response* reply) override {

    int ret = sendModuleMsgToAct(QUEUE_MSG_TYPE_MODULE,2);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
    wait_ack_module(60,&stMsgQueueAck,reply,2); 
    //wait_ack(20,&stMsgQueueAck,reply);
    //sleep(60);    

    //reply->set_statecode(0);
    printf("XR_AToB finished, grpc return\n");
    return Status::OK;
  }

  
};

int exitPhotoNotify = 0;

int g_count = 0;


typedef struct _cliCon
{
    ServerContext* context;
    ServerWriter<NotifyMes>* writer;
}cliCon;
std::list<cliCon> listClient;

class QPCRServiceImpl final : public QPCR::Service {  

  Status OpticalFilter(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,47);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(25,&stMsgQueueAck,reply,47);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status OpticalFilter1(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,54);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(25,&stMsgQueueAck,reply,54);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status Notify(ServerContext* context,
                      const gp::TryRequest* request,
                      ServerWriter<NotifyMes>* writer) override {
    
    // for (int i=0;i<10;i++) {
    //     NotifyMes nfm;
    //     nfm.set_content(std::to_string(i));
    //     writer->Write(nfm);
      
    // }

    NotifyMes nfm;
    nfm.set_content(std::to_string(g_count)+":");
    nfm.set_dev("qpcr camera");
    nfm.set_acttype(gp::PHOTO);
    nfm.set_actaccess(gp::NOT_ALLOWED);
    std::cout<<"write to stream"<<endl;
    writer->Write(nfm);
    std::list<cliCon>::iterator itCli;   
    if(listClient.size() == 0)
    {

      key_t key = ftok(msgNotifyQueuePath, keyNotifyMsg);
      if(key < 0)
      {
          perror("ftok");
          return Status::CANCELLED;
      }

      int msg_id = msgget(key, IPC_CREAT|0600);//IPC_CREAT|0600
      if(msg_id < 0)
      {
          perror("msgget");
          return Status::CANCELLED;
      }

      std::cout<<"in Notify, create msg success"<<std::endl;

      cliCon stCliCon;
      stCliCon.context = context;
      stCliCon.writer = writer;
      listClient.push_back(stCliCon);
      report_up_queue reportQueueMsg;
      int msgRet = 0;

      exitPhotoNotify = 0;
      while(!exitPhotoNotify)
      {
          msgRet = msgrcv( msg_id, &reportQueueMsg, sizeof(report_up) ,QUEUE_MSG_TYPE_REPORT,IPC_NOWAIT );
          if(msgRet>0)
          {
            printf("recved report msg queue\n");
            //printf("send to client!\n");
            //pstServer->handleReport(&g_count);
            g_count++; 

            NotifyMes nfm;
            nfm.set_content(std::to_string(g_count)+":");
            nfm.set_dev("qpcr camera");
            nfm.set_acttype(gp::PHOTO);
            nfm.set_actaccess(gp::ALLOWED);
            std::cout<<"write to stream"<<endl;
            itCli = listClient.begin();
            while(itCli!=listClient.end())
            { //itCli->context->
              if(!itCli->context->IsCancelled())
              {
                  itCli->writer->Write(nfm);
                  
              } 
              itCli++;             
            }                   
            
          }

          itCli = listClient.begin();
          while(itCli!=listClient.end())
          {
            if(itCli->context->IsCancelled())
            {
                std::list<cliCon>::iterator itCliTmp = itCli;
                itCli++;
                listClient.erase(itCliTmp);
                continue; 
                
            } 
            itCli++;             
          }

          if(listClient.empty())
          {
            cout<<"all client cancelled, exit now"<<endl;
            break;
          }
          usleep(1000);                    
      }
      exitPhotoNotify = 1;
      msgctl(msg_id,IPC_RMID,NULL);

    }
    else if(listClient.size()>=2)
    {
      return Status::CANCELLED;
    }
    else 
    {
      cliCon stCliCon;
      stCliCon.context = context;
      stCliCon.writer = writer;
      listClient.push_back(stCliCon);

      while(!exitPhotoNotify)
      {
        if(stCliCon.context->IsCancelled())
        {
          break;
        }
        usleep(100);
      }
    }
    return Status::OK;
    
  }

    Status Bath_X(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_BASH_X);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ACT_MSG_ERROR);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(25,&stMsgQueueAck,reply,SID_BASH_X);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status Bath_X1(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_BASH_X1);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ACT_MSG_ERROR);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(25,&stMsgQueueAck,reply,SID_BASH_X1);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status Bath_Z(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendModuleMsgToAct(request,QUEUE_MSG_TYPE_MODULE,I_MODULE_BATHZMOVE);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    //wait_ack(25,&stMsgQueueAck,reply,I_MODULE_BATHZMOVE);  

    wait_ack_module(30,&stMsgQueueAck,reply,I_MODULE_BATHZMOVE); 

    //reply->set_statecode(0);
    return Status::OK;
    // #define SID_BASH_Z 46
    // int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_BASH_Z);
    // if(ret)
    // {
    //   reply->set_statecode(1);
    //   reply->set_errornum(ACT_MSG_ERROR);
    //   return Status::OK;
    // }
    
    // msgQueueAck stMsgQueueAck;
    // memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    // wait_ack(25,&stMsgQueueAck,reply,SID_BASH_Z);    

    // //reply->set_statecode(0);
    // return Status::OK;
  }

  Status Bath_Z1(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendModuleMsgToAct(request,QUEUE_MSG_TYPE_MODULE,I_MODULE_BATH1ZMOVE);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    //wait_ack(25,&stMsgQueueAck,reply,I_MODULE_BATHZMOVE);  

    wait_ack_module(30,&stMsgQueueAck,reply,I_MODULE_BATH1ZMOVE); 

    //reply->set_statecode(0);
    return Status::OK;
  }
};

class DJQServiceImpl final : public DJ_Qpcr::Service {
  Status DJ_X(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,49);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,49);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_Y(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_DJ_Y);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_DJ_Y);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_Z(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_DJ_Z);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_DJ_Z);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_Pump(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_DJ_PUMP);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_DJ_PUMP);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_Clean(ServerContext* context, const EmptyRequest* request,
                  Response* reply) override {

    int ret = sendModuleMsgToAct(QUEUE_MSG_TYPE_MODULE,I_MODULE_DJLIQUID);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
    wait_ack_module(120,&stMsgQueueAck,reply,I_MODULE_DJLIQUID); 
    //wait_ack(20,&stMsgQueueAck,reply);
    //sleep(60);    

    //reply->set_statecode(0);
    printf("DJ_Clean finished, grpc return\n");
    return Status::OK;
  }

  
  Status DJ_AddSample(ServerContext* context, const DjAddSampleParam* request,
                  Response* reply) override {


    DjAddSampleParam paramIn;
    std::cout<<"enter in DJ_AddSample"<<std::endl;
    //memset(&paramIn,0,sizeof(DjAddSampleParam));
    //paramIn.set_traceline("Aa20,Ab20,Ac20,Ad20,Ae20,Af20,Ag20,Ah20,\
    //Bh20,Bg20,Bf20,Be20,Bd20,Bc20,Bb20,Ba20,\
    //Ca20,Cb20,Cc20,Cd20,Ce20,Cf20,Cg20,Ch20,\
    //");

    paramIn.set_traceline("Bh20,Bg20,Bf20,Be20,Bd20,Bc20,Bb20,Ba20,\
Ca20,Cb20,Cc20,Cd20,Ce20,Cf20,Cg20,Ch20");
    paramIn.set_initx(400);
    paramIn.set_inity(0);
    paramIn.set_initz(30000);

    paramIn.set_deltax(480);
    paramIn.set_deltay(8571);

    paramIn.set_quantityair(5);
    paramIn.set_quantitydrop(5);
    paramIn.set_quantitysuck(320);

    procDjAddSample(request,reply);
    //wait_ack(20,&stMsgQueueAck,reply);
    //sleep(60);    

    //reply->set_statecode(0);
    //if(ret)
    //{
    //  reply->set_statecode(2);
    //  reply->set_errornum(ret);
    //}

    printf("DJ_AddSample finished, grpc return\n");
    return Status::OK;
  }

  Status DJ_Move(ServerContext* context, const DjActParam* request,
                  Response* reply) override {

    std::ofstream outfile;

    outfile.open(FILE_DJ_TRACE, std::ofstream::out | std::ofstream::trunc | std::ofstream::binary);
    const char * data = request->traceline().c_str();
    outfile.write(data, request->traceline().length());

    outfile.close();

    int ret = sendDjMsgToAct(request,QUEUE_MSG_TYPE_MODULE,I_FILE_DJ);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
    wait_ack_module(120,&stMsgQueueAck,reply,I_FILE_DJ); 
    //wait_ack(20,&stMsgQueueAck,reply);
    //sleep(60);    

    //reply->set_statecode(0);
    printf("DJ_Move finished, grpc return\n");
    return Status::OK;
  }
  

  Status DJ_OutCleanPump(ServerContext* context, const DjLiquidParam* request,
                  Response* reply) override {
    
    const unsigned int idOutCleanPump = 0;

    int ret = sendMsgToDjLiquidAct(request,idOutCleanPump);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(request->duration()/1000 + 5,&stMsgQueueAck,reply,84+idOutCleanPump);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_InCleanPump(ServerContext* context, const DjLiquidParam* request,
                  Response* reply) override {
    
    const unsigned int idInCleanPump = 1;

    int ret = sendMsgToDjLiquidAct(request,idInCleanPump);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(request->duration()/1000 + 5,&stMsgQueueAck,reply,84+idInCleanPump);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_WasteLiquidPump(ServerContext* context, const DjLiquidParam* request,
                  Response* reply) override {
    
    const unsigned int idwasteLiquidPump = 3;

    int ret = sendMsgToDjLiquidAct(request,idwasteLiquidPump);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(request->duration()/1000 + 5,&stMsgQueueAck,reply,84+idwasteLiquidPump);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status DJ_InCleanValve(ServerContext* context, const DjLiquidParam* request,
                  Response* reply) override {
    
    const unsigned int idInCleanValve = 2;

    int ret = sendMsgToDjLiquidAct(request,idInCleanValve);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(request->duration()/1000 + 5,&stMsgQueueAck,reply,84+idInCleanValve);    

    //reply->set_statecode(0);
    return Status::OK;
  }

};

class LogisticsServiceImpl final : public Logistics_Qpcr::Service {
  Status Logistics_X(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_Logistics_X);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_Logistics_X);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status Logistics_Jaw(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_Logistics_JAW);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_Logistics_JAW);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status Logistics_JawZ(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_Logistics_JawZ);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_Logistics_JawZ);    

    //reply->set_statecode(0);
    return Status::OK;
  }

  Status Logistics_Up(ServerContext* context, const AxisMoveParam* request,
                  Response* reply) override {

    int ret = sendMsgToAct(request,QUEUE_MSG_TYPE_UIM,SID_DJ_PUMP);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));

    wait_ack(10,&stMsgQueueAck,reply,SID_DJ_PUMP);    

    //reply->set_statecode(0);
    return Status::OK;
  }

    Status trans_board(ServerContext* context, const EmptyRequest* request, Response* reply) override {

    int ret = sendModuleMsgToAct(QUEUE_MSG_TYPE_MODULE,I_FILE_TRANS);
    if(ret)
    {
      reply->set_statecode(1);
      reply->set_errornum(ret);
      return Status::OK;
    }
    
    msgQueueAck stMsgQueueAck;
    memset(&stMsgQueueAck,0,sizeof(msgQueueAck));
    wait_ack_module(120,&stMsgQueueAck,reply,I_FILE_TRANS); 
    //wait_ack(20,&stMsgQueueAck,reply);
    //sleep(60);    

    //reply->set_statecode(0);
    printf("XR_AToB finished, grpc return\n");
    return Status::OK;
  }

  
};


void RunServer() {
  std::string server_address("0.0.0.0:50051");

  ModuleServiceImpl serviceModule;
  QPCRServiceImpl serviceQpcr;

  DJQServiceImpl serviceDjQ;

  LogisticsServiceImpl serviceLogistics;

  ServerBuilder builder;
  // Listen on the given address without any authentication mechanism.
  builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
  // Register "service" as the instance through which we'll communicate with
  // clients. In this case it corresponds to an *synchronous* service.

  builder.RegisterService(&serviceModule);
  builder.RegisterService(&serviceQpcr);
  //builder.RegisterService(&serviceDjQ); 
  builder.RegisterService(&serviceLogistics); 
  // Finally assemble the server.
  std::unique_ptr<Server> server(builder.BuildAndStart());
  std::cout << "Server listening on " << server_address << std::endl;

  // Wait for the server to shutdown. Note that some other thread must be
  // responsible for shutting down the server for this call to ever return.
  server->Wait();
}


int main(int argc, char** argv) {

  key_t key = ftok(msgQueueKeyPath, 0x1234);
  if(key < 0)
  {
      perror("ftok");
      return -1;
  }

  int msg_id = msgget(key, IPC_CREAT|0600);//IPC_CREAT|0600
  if(msg_id < 0)
  {
      perror("msgget");
      return -1;
  }
  g_msg_id = msg_id;
  listClient.clear();
  
  CActionMange eleCtlManage;
  CActionMange moduleManage;
  
  g_ptrEleCtlManage = &eleCtlManage;
  g_ptrModuleManage = &moduleManage;
  appAckRecvexitFlag = 0;
  pthread_t appAckRecvHandl = 0;
  pthread_create(&appAckRecvHandl,NULL,funcRecvAck,&msg_id);

  RunServer();


  appAckRecvexitFlag = 1;
  void * threadRet = NULL;
  pthread_join(appAckRecvHandl,&threadRet);

  if(threadRet)
  {
    free(threadRet);
  }

  return 0;
}


int  sendMsgToAct(const AxisMoveParam* request,int msgType,
     unsigned char sidIn,unsigned char indexOnBoard)
{
    msg_ctl_uim msgFrame;
    int ret = 0;

    int actId = sidIn;
    if(msgType == QUEUE_MSG_TYPE_BOARDS)
    {
        actId = 80 + indexOnBoard;
    }

    if(g_ptrEleCtlManage->getActStatus(actId) == ACT_RUNNING)
    {
      ret = ACT_ALREADY_RUNNINMG;
      return ret;
    }

    memset(&msgFrame,0,sizeof(msg_ctl_uim));
    msgFrame.ctlFrame.un_cmd.moveCtl.speed = request->speed();
    msgFrame.ctlFrame.sid = sidIn;
    msgFrame.ctlFrame.opcode = MOVE;
    msgFrame.ctlFrame.un_cmd.moveCtl.inc_speed = request->acc();
    msgFrame.ctlFrame.un_cmd.moveCtl.dec_speed = request->dec();
    msgFrame.ctlFrame.un_cmd.moveCtl.position = request->position();
    msgFrame.ctlFrame.un_cmd.moveCtl.ele_index = indexOnBoard;

    msgFrame.type = msgType;

    g_ptrEleCtlManage->setActStatus(actId,ACT_RUNNING);
    if(msgsnd(g_msg_id, (void*)&msgFrame, sizeof(ctl_uim), 0) < 0)
    {
        printf("msg send failed\n");
        g_ptrEleCtlManage->setActStatus(actId,ACT_FINISHED);
        ret = 1;
    }
    else
    {        
        printf("msg send success,type is %d,opcode[%d]\n",msgFrame.type,msgFrame.ctlFrame.opcode);
        ret = 0;
    }
    return ret;
}

int  sendMsgToDjLiquidAct(const DjLiquidParam* request,unsigned int idPump)
{
    msg_ctl_uim msgFrame;
    int ret = 0;

    int actId = 84+idPump;

    if(g_ptrEleCtlManage->getActStatus(actId) == ACT_RUNNING)
    {
      ret = ACT_ALREADY_RUNNINMG;
      return ret;
    }

    memset(&msgFrame,0,sizeof(msg_ctl_uim));
    
    msgFrame.ctlFrame.sid = SYSTEM_CTRL_BOARD;
    msgFrame.ctlFrame.opcode = request->startorstop()?CENTRE_START:CENTRE_STOP;
    msgFrame.ctlFrame.un_cmd.djLiquidParam.chanNum = idPump;
    msgFrame.ctlFrame.un_cmd.djLiquidParam.paramType = SYSCTL_LIQUID;
    msgFrame.ctlFrame.un_cmd.djLiquidParam.duration = request->duration();

    msgFrame.type = QUEUE_MSG_TYPE_BOARDS;

    g_ptrEleCtlManage->setActStatus(actId,ACT_RUNNING);
    if(msgsnd(g_msg_id, (void*)&msgFrame, sizeof(ctl_uim), 0) < 0)
    {
        printf("msg send failed\n");
        g_ptrEleCtlManage->setActStatus(actId,ACT_FINISHED);
        ret = 1;
    }
    else
    {        
        printf("msg send success,type is %d,opcode[%d]\n",msgFrame.type,msgFrame.ctlFrame.opcode);
        ret = 0;
    }
    return ret;
}

int  sendModuleMsgToAct(const void * requestIn,int msgType,int moduleIdIn)
{
    module_queue_msg ctlFrame;
    memset(&ctlFrame,0,sizeof(module_queue_msg));
    int ret =0;

      

    if(g_ptrModuleManage->getActStatus(moduleIdIn) == ACT_RUNNING)
    {
      ret = ACT_ALREADY_RUNNINMG;
      return ret;
    }
    
    
    ctlFrame.type = msgType;
    ctlFrame.moduleMsg.moduleId = moduleIdIn;
    
    if(moduleIdIn == I_MODULE_BATHZMOVE || I_MODULE_BATH1ZMOVE == moduleIdIn)
    {
        const AxisMoveParam * request = (const AxisMoveParam*)requestIn;
        move_param * pstMoveParam = &ctlFrame.moduleMsg.un_param.moveParam;
        pstMoveParam->speed = request->speed();
        pstMoveParam->dec_speed = request->dec();
        pstMoveParam->inc_speed = request->acc();
        pstMoveParam->pos = request->position();
    }
    else if(moduleIdIn == I_MODULE_DJREAGENT)
    {
        dj_reagent * djReagentParam = &ctlFrame.moduleMsg.un_param.djReagentParam;
        dj_reagent * ptrParamIn = (dj_reagent *)requestIn;
        memcpy(djReagentParam,ptrParamIn,sizeof(dj_reagent));
    }


    g_ptrModuleManage->setActStatus(moduleIdIn,ACT_RUNNING);
    if(msgsnd(g_msg_id, (void*)&ctlFrame, sizeof(module_msg), 0) < 0)
    {
        printf("msg send failed\n");
        g_ptrModuleManage->setActStatus(moduleIdIn,ACT_FINISHED);
        ret = 1;
    }
    else
    {
        
        printf("msg send success,type is %d,msgId[%d]\n",ctlFrame.type,ctlFrame.moduleMsg.moduleId);
        ret = 0;
    }
    return ret;
}

int  sendDjMsgToAct(const DjActParam* request,int msgType,int moduleIdIn)
{
    module_queue_msg ctlFrame;
    int ret =0;

    if(g_ptrModuleManage->getActStatus(moduleIdIn) == ACT_RUNNING)
    {
      ret = ACT_ALREADY_RUNNINMG;
      return ret;
    }

    ctlFrame.type = msgType;
    ctlFrame.moduleMsg.moduleId = moduleIdIn;
    
    dj_move_param * pstMoveParam = &ctlFrame.moduleMsg.un_param.djMoveParam;
    pstMoveParam->deltaX = request->deltax();
    pstMoveParam->deltaY = request->deltay();
    pstMoveParam->initX = request->initx();
    pstMoveParam->initY = request->inity();
    pstMoveParam->initZ = request->initz();
    pstMoveParam->numStepsOneAct = request->numsteponeact();

    g_ptrModuleManage->setActStatus(moduleIdIn,ACT_RUNNING);
    if(msgsnd(g_msg_id, (void*)&ctlFrame, sizeof(module_msg), 0) < 0)
    {
        printf("msg send failed\n");
        g_ptrModuleManage->setActStatus(moduleIdIn,ACT_FINISHED);
        ret = 1;
    }
    else
    {
        
        printf("msg send success,type is %d,msgId[%d]\n",ctlFrame.type,ctlFrame.moduleMsg.moduleId);
        ret = 0;
    }
    return ret;
}

int  sendModuleMsgToAct(int msgType,int moduleIdIn)
{
    module_queue_msg ctlFrame;
    int ret =0;

    if(g_ptrModuleManage->getActStatus(moduleIdIn) == ACT_RUNNING)
    {
      ret = ACT_ALREADY_RUNNINMG;
      return ret;
    }

    ctlFrame.type = msgType;
    ctlFrame.moduleMsg.moduleId = moduleIdIn;
    
    g_ptrModuleManage->setActStatus(moduleIdIn,ACT_RUNNING);
    if(msgsnd(g_msg_id, (void*)&ctlFrame, sizeof(module_msg), 0) < 0)
    {
        printf("msg send failed\n");
        g_ptrModuleManage->setActStatus(moduleIdIn,ACT_FINISHED);
        ret = 1;
    }
    else
    {        
        printf("msg send success,type is %d,msgId[%d]\n",ctlFrame.type,ctlFrame.moduleMsg.moduleId);
        ret = 0;
    }
    return ret;
}

int wait_ack_module(int timeOut,msgQueueAck * ackMsg,Response* reply,int moduleId)
{
  int tmpTimeOut = timeOut;
  int ret = 0;
  if(tmpTimeOut==0)
  {
    tmpTimeOut = 1000;
  }
  else
  {
    tmpTimeOut*=1000;
  }

  int counter = tmpTimeOut/20;

  int statusCodeRecv = 0;
  int errNumRecv = 0;

  while(counter>0)
  {
    if(g_ptrModuleManage->getActStatus(moduleId,&statusCodeRecv,&errNumRecv) != ACT_RUNNING)
    {
      break;
    }
    usleep(20000);

    counter--;
  }

  if(counter<=0)
  {
    reply->set_statecode(2);
    reply->set_errornum(ACT_TIMEOUT_GRPC);
    ret = 1;

    g_ptrModuleManage->setActStatus(moduleId,ACT_TIMEDOUT_GRPC);
  }
  else
  {  
    if(statusCodeRecv)
    {
      reply->set_errornum(errNumRecv);
      reply->set_statecode(2);
      ret = 1;
    }
    else
    {
      reply->set_errornum(100);
      reply->set_statecode(100);
      ret = 0;
    }
    
  }

}

int wait_ack(int timeOut,msgQueueAck * ackMsg,Response* reply,int sid)
{
  int tmpTimeOut = timeOut;
  int ret = 0;
  if(tmpTimeOut==0)
  {
    tmpTimeOut = 1000;
  }
  else
  {
    tmpTimeOut*=1000;
  }

  int counter = tmpTimeOut/20;
  
  int statusCodeRecv = 0;
  int errNumRecv = 0;
  while(counter>0)
  {
    if(g_ptrEleCtlManage->getActStatus(sid,&statusCodeRecv,&errNumRecv) != ACT_RUNNING)
    {
        break;
    }
    usleep(10000);

    counter--;
  }

  if(counter<=0)
  {
    reply->set_statecode(2);
    reply->set_errornum(ACT_TIMEOUT_GRPC);
    ret = 1;
    g_ptrEleCtlManage->setActStatus(sid,ACT_TIMEDOUT_GRPC);
  }
  else
  {  
    if(statusCodeRecv)
    {
      reply->set_errornum(errNumRecv);
      reply->set_statecode(2);
      ret = 1;
    }
    else
    {
      reply->set_errornum(100);
      reply->set_statecode(100);
      ret = 0;
    }
    
  }

}
